package de.akabahn.ebd.stw.zdxfc.prs.fst.pair;

import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.BIT0;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.BIT1;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.FAHRSTRASSE_AG;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.GLEIS_1;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.GLEIS_102;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.MELDER_SIGNAL_C2;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.MELDER_TASTE_AG;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.SIGNAL_C2;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.SIGNAL_C3;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.SIGNAL_CV4;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.STRECKE_1231;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.VERSCHLUSS;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.WEICHE_1;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.WEICHE_2;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.WEICHE_3;
import static de.akabahn.ebd.stw.zdxfc.prs.ZDXFCConstants.WEICHE_4;
import de.akabahn.ebd.comm.dbd.DBDParameter;
import de.akabahn.ebd.dbd.SwitchPosition;
import de.akabahn.ebd.dbd.impl.DBDSignalF;
import de.akabahn.ebd.stw.zdxfc.prs.ZDXFCMain;
import de.akabahn.ebd.stw.zdxfc.prs.fst.FahrStrasse;

/**
 * Fahrstrasse <code>AG</code><br>
 * Start: Signal C2<br>
 * Ziel: Signal C10<br>
 * <br>
 * Fahrstrassen Weichen:<br>
 * <ol>
 * <li>Weiche 1, Rechtslage</li>
 * <li>Weiche 2, Rechtslage (Flankenschutz)</li>
 * <li>Weiche 3, Linkslage</li>
 * <li>Weiche 4, Linkslage (Flankenschutz)</li>
 * </ol>
 * <br>
 * Fahrstrassen Gleise:<br>
 * <ol>
 * <li>Gleis 102, muss frei sein</li>
 * <li>Gleis 1 (Zielgleis, darf besetzt sein)</li>
 * </ol>
 * <br>
 * Fahrstrassen Signale:<br>
 * <ol>
 * <li>Signal C2, Startsignal, kein manueller Haltfall</li>
 * <li>Signal Cv4, Lichtschutz</li>
 * <li>Signal C3, Lichtschutz</li>
 * </ol>
 * 
 * @author Peter Eimann
 * @since 1.0
 * @version 1.2
 */
public class FahrStrasseAG extends FahrStrasse {

	/**
	 * Initialisierung mit ID <code>AG</code> und DBD-Name des Tastenmelders <code>S31TAGS</code>
	 * 
	 * @param main Referenz auf die Hauptklasse
	 */
	public FahrStrasseAG(ZDXFCMain main) {
		super(FAHRSTRASSE_AG, MELDER_TASTE_AG, main, SIGNAL_C2);
		
		fstWeichen = new FstWeiche[] {
				new FstWeiche(WEICHE_1, SwitchPosition.RIGHT, false),
				new FstWeiche(WEICHE_2, SwitchPosition.RIGHT, true),
				new FstWeiche(WEICHE_3, SwitchPosition.LEFT, false),
				new FstWeiche(WEICHE_4, SwitchPosition.LEFT, true)
		};
		
		fstGleise = new FstGleis[] {
				new FstGleis(GLEIS_102, true),
				new FstGleis(GLEIS_1, false)
		};
		
		fstSignale = new FstSignal[] {
				new FstSignal(SIGNAL_C2, true),
				new FstSignal(SIGNAL_CV4, false),
				new FstSignal(SIGNAL_C3, false)
		};
	}

	/**
	 * Wird die Fahrstrasse verschlossen, wird der Verschlussmelder des Signals mit Dauerlicht ausgeleuchtet,
	 * anderenfalls wird Blinklicht angeschaltet, wenn das Streckengleis zwischen Martinstein und Chateauprix
	 * besetzt ist und die Ausleuchtung geloescht, wenn das Streckengleis frei ist.
	 */
	@Override
	public void setVerschlossen(boolean verschlossen) {
		super.setVerschlossen(verschlossen);

		if (verschlossen) {
			main.getDbd().set(MELDER_SIGNAL_C2[VERSCHLUSS], BIT0);
		} else {
			if (main.getGleis(STRECKE_1231).isBesetzt()) {
				main.getDbd().set(MELDER_SIGNAL_C2[VERSCHLUSS], BIT1);
			} else {
				main.getDbd().set(MELDER_SIGNAL_C2[VERSCHLUSS], 0);
			}
		}
	}

	/**
	 * Verschluss:<br>
	 * <ul>
	 * <li>Verschluss der Fahrstrasse, wenn das Streckengleis besetzt ist (ZAp)</li>
	 * </ul>
	 * <br>
	 * Startsignal C2:<br>
	 * <ul>
	 * <li>Fahrstrassen-ID <code>AG</code></li>
	 * <li>Signalbegriff <code>S</code> wenn Gleis 1 besetzt ist, ansonsten <code>A</code></li>
	 * </ul>
	 * <br>
	 * Rangiersignal CV4:<br>
	 * <ul>
	 * <li>Signalbegriff <code>M</code></li>
	 * </ul>
	 */
	@Override
	public void einstellenProcess() {
		if (main.getGleis(STRECKE_1231).isBesetzt()) {
			setVerschlossen(true);
		}
		
		main.getSignal(SIGNAL_CV4).stellen(DBDSignalF.M);
		main.getSignal(SIGNAL_C2).setFahrStrassenId(id);
		if (main.getGleis(GLEIS_1).isBesetzt()) {
			main.getSignal(SIGNAL_C2).stellen(DBDSignalF.S_BAL);
		} else {
			main.getSignal(SIGNAL_C2).stellen(DBDSignalF.AAP);
		}
	}

	/**
	 * Haltfall Signal <code>Cv4</code>
	 */
	@Override
	public void aufloesenProcess() {
		main.getSignal(SIGNAL_CV4).setHaltfall();
	}

	/**
	 * Ueberpruefte Bedingungen:<br>
	 * <ol>
	 * <li>Aufloesezeit muss kleiner gleich 0 sein</li>
	 * <li>Haltfall Signal <code>C2</code></li>
	 * <li>Haltfall Signal <code>CV4</code></li>
	 * </ol>
	 * <br>
	 * Aktionen bei erfolgreicher Pruefung:<br>
	 * <ul>
	 * <li><i>keine</i></li>
	 * </ul>
	 */
	@Override
	public boolean aufloeseBedinungenOk() {
		return main.getSignal(SIGNAL_C2).isHalt()
			&& main.getSignal(SIGNAL_CV4).isHalt()
			&& getAufloeseZeit() <= 0;
	}

	/**
	 * Ueberwachte Elemente:<br>
	 * <ol>
	 * <li>Weiche 1</li>
	 * <li>Weiche 3</li>
	 * <li>Gleis 1</li>
	 * <li>Gleis 102</li>
	 * </ol>
	 */
	@Override
	public void onChangeBesetzung(DBDParameter dbd) {
		if (dbd.getId().equals(GLEIS_102)) {
			onChangeGleis102();
		} else if (dbd.getId().equals(WEICHE_1)) {
			onChangeWeiche1();
		} else if (dbd.getId().equals(WEICHE_3)) {
			onChangeWeiche3();
		} else if (dbd.getId().equals(GLEIS_1)) {
			onChangeGleis1();
		}
	}

	/**
	 * Ueberwachung des Gleises 102:<br>
	 * Aktionen beim Besetzen:<br>
	 * <ol>
	 * <li>Aufloesung Gleis 102 vorbereiten</li>
	 * <li>Haltfall Startsignale</li>
	 * </ol>
	 * <br>
	 * Aktionen beim Freifahren:<br>
	 * <ol>
	 * <li>Verschluss der Fahrstrasse aufloesen</li>
	 * <li>Ausleuchtung Tastenmelder der Fahrstrasse loeschen</li>
	 * <li>Gleis 102 inaktiv setzen</li>
	 * </ol> 
	 */
	private void onChangeGleis102() {
		if (main.getGleis(GLEIS_102).isBesetzt()) {
			main.getGleis(GLEIS_102).setAufloesenVorbereiten(true);
			haltfallStartsignale();
		} else {
			if (main.getGleis(GLEIS_102).isAufloesenVorbereiten() && main.getWeiche(WEICHE_1).isBesetzt()) {
				main.getGleis(GLEIS_102).setAufloesenVorbereiten(false);
				main.getGleis(GLEIS_102).setAktiv(false);
				setVerschlossen(false);
				main.getDbd().set(getTastenMelderId(), 0);
			}
		}
	}

	/**
	 * Ueberwachung der Weiche 1:<br>
	 * Aktionen beim Besetzen:<br>
	 * <ol>
	 * <li>Haltfall Startsignale</li>
	 * <li>Haltfall Signal <code>CV4</code></li>
	 * <li>Aufloesung Weiche 1 vorbereiten</li>
	 * </ol>
	 * <br>
	 * Aktionen beim Freifahren:<br>
	 * <ol>
	 * <li>Flankenschutz <code>Weiche 2</code> aufloesen</li>
	 * <li>Weiche 1 inaktiv setzen</li>
	 * </ol> 
	 */
	private void onChangeWeiche1() {
		if (main.getWeiche(WEICHE_1).isBesetzt()) {
			main.getSignal(SIGNAL_CV4).setHaltfall();
			haltfallStartsignale();
			main.getWeiche(WEICHE_1).setAufloesenVorbereiten(true);
		} else {
			if (main.getWeiche(WEICHE_1).isAufloesenVorbereiten() && !main.getGleis(GLEIS_102).isBesetzt() && main.getWeiche(WEICHE_3).isBesetzt()) {
				main.getWeiche(WEICHE_1).setAufloesenVorbereiten(false);
				main.getWeiche(WEICHE_1).setAktiv(false);
				main.getWeiche(WEICHE_2).setFlankenSchutz(false);
			}
		}
	}

	/**
	 * Ueberwachung der Weiche 3:<br>
	 * Aktionen beim Besetzen:<br>
	 * <ol>
	 * <li>Haltfall Startsignale</li>
	 * <li>Aufloesung Weiche 3 vorbereiten</li>
	 * </ol>
	 * <br>
	 * Aktionen beim Freifahren:<br>
	 * <ol>
	 * <li>Flankenschutz <code>Weiche 4</code> aufloesen</li>
	 * <li>Fahrstrasse und <code>Gleis 1</code> inaktiv setzen</li>
	 * <li>Weiche 3 inaktiv setzen</li>
	 * </ol> 
	 */
	private void onChangeWeiche3() {
		if (main.getWeiche(WEICHE_3).isBesetzt()) {
			haltfallStartsignale();
			main.getWeiche(WEICHE_3).setAufloesenVorbereiten(true);
		} else {
			if (main.getWeiche(WEICHE_3).isAufloesenVorbereiten() && !main.getWeiche(WEICHE_1).isBesetzt() && main.getGleis(GLEIS_1).isBesetzt()) {
				main.getWeiche(WEICHE_3).setAufloesenVorbereiten(false);
				main.getWeiche(WEICHE_3).setAktiv(false);
				main.getWeiche(WEICHE_4).setFlankenSchutz(false);
				main.getGleis(GLEIS_1).setAktiv(false);
				setAktiv(false);
			}
		}
	}

	/**
	 * Ueberwachung des Gleises 1:<br>
	 * Aktionen beim Besetzen:<br>
	 * <ol>
	 * <li>Startsignale</li>
	 * </ol>
	 * <br>
	 * Aktionen beim Freifahren:<br>
	 * <ol>
	 * <li>Wenn die Fahrstrasse noch eingestellt und das Signal C2 <code>S</code> zeigt, wird das Gleis 1 aktiv
	 * gesetzt und Signal C2 zeigt <code>A</code></li>
	 * </ol> 
	 */
	private void onChangeGleis1() {
		if (main.getGleis(GLEIS_1).isBesetzt()) {
			haltfallStartsignale();
		} else {
			if (id.equals(main.getSignal(SIGNAL_C2).getFahrStrassenId())
				&& main.getSignal(SIGNAL_C2).getSignalBegriff() == DBDSignalF.S_BAL) {
				main.getGleis(GLEIS_1).setAktiv(true);
				main.getSignal(SIGNAL_C2).stellen(DBDSignalF.AAP);
			}
		}
	}
}
